#include "PluginHandlerDialog.h"
#include "ui_PluginHandlerDialog.h"

#include <QFileDialog>

PluginHandlerDialog::PluginHandlerDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::PluginHandlerDialog),
    currentPluginHandler(1)
{
    ui->setupUi(this);

    connect(ui->pluginTabs, SIGNAL(currentChanged(int)), this, SLOT(pluginTabChanged(int)));
    connect(ui->addPluginsButton, SIGNAL(clicked()), this, SLOT(addPluginDirectory()));
    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(hide()));
}

PluginHandlerDialog::~PluginHandlerDialog()
{
    delete ui;
}

void PluginHandlerDialog::pluginTabChanged(int i) {
    currentPluginHandler = i;
}

void PluginHandlerDialog::change(QTreeWidgetItem* item) {
    disconnect(item->treeWidget(), SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(change(QTreeWidgetItem*)));
    if (item->childCount() > 0) {
        // item is parent
        Qt::CheckState checkState = item->checkState(0);
        if (checkState == Qt::Unchecked) {
            for (int i = 0; i < item->childCount(); i++) {
                QTreeWidgetItem* other = item->child(i);
                if (other->checkState(0) == Qt::Checked) {
                    other->setCheckState(0, checkState);
                    item->setData(2, Qt::UserRole, i);
                    getCurrentPluginHandler()->setActivePlugin(item->text(1).toStdString(), other->text(1).toStdString(), false);
                }
            }
        } else {
            int index = item->data(2, Qt::UserRole).toInt();
            if (index < item->childCount()) {
                item->child(index)->setCheckState(0, checkState);
                getCurrentPluginHandler()->setActivePlugin(item->text(1).toStdString(), item->child(index)->text(1).toStdString(), true);
            }
         }
    } else {
        // item is child
        QTreeWidgetItem* parent = item->parent();
        Qt::CheckState checkState = item->checkState(0);
        parent->setCheckState(0, checkState);
        if (checkState == Qt::Unchecked) {
            parent->setData(2, Qt::UserRole, parent->indexOfChild(item));
            getCurrentPluginHandler()->setActivePlugin(parent->text(1).toStdString(), item->text(1).toStdString(), false);
        } else {
            for (int i = 0; i < parent->childCount(); i++) {
                QTreeWidgetItem* other = parent->child(i);
                if (other->checkState(0) == Qt::Checked && other != item) {
                    other->setCheckState(0, Qt::Unchecked);
                    getCurrentPluginHandler()->setActivePlugin(parent->text(1).toStdString(), other->text(1).toStdString(), false);
                }
            }
            getCurrentPluginHandler()->setActivePlugin(parent->text(1).toStdString(), item->text(1).toStdString(), true);
        }
    }
    connect(item->treeWidget(), SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(change(QTreeWidgetItem*)));
}

void PluginHandlerDialog::addPluginDirectory() {
    QSettings settings;
    std::string path = QFileDialog::getExistingDirectory(this, QString("Choose plugin directory"), settings.value("directorypaths/plugins", "").toString()).toStdString();
    if (!path.empty()) {
        settings.setValue("directorypaths/plugins", QString::fromStdString(path));
        boost::shared_ptr<IPluginHandler> pluginHandler = getCurrentPluginHandler();
        if (pluginHandler && pluginHandler->addPlugins(path)) {
            ui->pluginTabs->removeTab(currentPluginHandler);
            ui->pluginTabs->insertTab(currentPluginHandler, createPluginHandlerWidget(pluginHandler), QString::fromStdString(pluginHandler->getName()));
        }
    }
}

void PluginHandlerDialog::addPluginHandler(boost::shared_ptr<IPluginHandler> pluginHandler) {
    int index = containsPluginHandler(pluginHandler);
    if (index == -1) {
        pluginHandlerList.push_back(pluginHandler);
        ui->pluginTabs->addTab(createPluginHandlerWidget(pluginHandler), QString::fromStdString(pluginHandler->getName()));
    }
    else {
        ui->pluginTabs->removeTab(index);
        ui->pluginTabs->insertTab(index, createPluginHandlerWidget(pluginHandler), QString::fromStdString(pluginHandler->getName()));
    }
}

void PluginHandlerDialog::removePluginHandler(const std::string &name) {
    int index = containsPluginHandler(name);
    if (index >= 0) {
        pluginHandlerList.erase(pluginHandlerList.begin() + index);
        ui->pluginTabs->removeTab(index);
        if (currentPluginHandler == index) {
            currentPluginHandler = 0;
            ui->pluginTabs->setCurrentIndex(0);
        }
    }
}

QTreeWidget* PluginHandlerDialog::createPluginHandlerWidget(boost::shared_ptr<IPluginHandler> pluginHandler) {
    QTreeWidget* treeWidget = new QTreeWidget(ui->pluginTabs);
    treeWidget->setColumnCount(2);
    treeWidget->setHeaderLabels({QString("Active"), QString("Plugin")});

    QList<QTreeWidgetItem*> items;
    for (const auto &plugins : pluginHandler->getPlugins()) {
        QTreeWidgetItem* item = new QTreeWidgetItem(treeWidget);
        item->setCheckState(0, Qt::Unchecked);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
        item->setText(1, QString::fromStdString(plugins.first));
        for (const auto &plugin : plugins.second) {
            QTreeWidgetItem* item2 = new QTreeWidgetItem(item);
            if (plugin->active) item->setCheckState(0, Qt::Checked);
            item2->setCheckState(0, plugin->active ? Qt::Checked : Qt::Unchecked);
            item2->setFlags(item2->flags() | Qt::ItemIsUserCheckable);
            item2->setText(1, QString::fromStdString(plugin->path));
            item2->setToolTip(1, QString::fromStdString(plugin->path));
            item->addChild(item2);
        }
        items.append(item);
    }

    QObject::connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(change(QTreeWidgetItem*)));

    treeWidget->insertTopLevelItems(0, items);
    treeWidget->expandAll();
    treeWidget->resizeColumnToContents(0);
    treeWidget->collapseAll();
    return treeWidget;
}

boost::shared_ptr<IPluginHandler> PluginHandlerDialog::getCurrentPluginHandler() {
    if (currentPluginHandler >= (int)pluginHandlerList.size()) return nullptr;
    else return pluginHandlerList[currentPluginHandler];
}

int PluginHandlerDialog::containsPluginHandler(boost::shared_ptr<IPluginHandler> pluginHandler) {
    return containsPluginHandler(pluginHandler->getName());
}

int PluginHandlerDialog::containsPluginHandler(std::string name) {
    int index = 0;
    for (auto p : pluginHandlerList) {
        if (p->getName() == name) return index;
        index++;
    }
    return -1;
}
